package com.jsy.testlock.lockimpl.redis;


import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author: SongyangJi
 * @description:
 * @since: 2021/11/29
 */


public class RedisLock {


    private final String lock_key = "redis_lock"; //锁键

    protected long internalLockLeaseTime = 30000;//锁过期时间

    private final long timeout = 999999; //获取锁的超时时间


    //SET命令的参数
    SetParams params = SetParams.setParams().nx().px(internalLockLeaseTime);

    JedisPool jedisPool = new JedisPool("localhost");


    public boolean lock(String id) {
        Jedis jedis = jedisPool.getResource();
        long start = System.currentTimeMillis();
        try {
            for (; ; ) {
                //SET命令返回OK ，则证明获取锁成功
                String lock = jedis.set(lock_key, id, params);
                if ("OK".equals(lock)) {
                    return true;
                }
                //否则循环等待，在timeout时间内仍未获取到锁，则获取失败
                long l = System.currentTimeMillis() - start;
                if (l >= timeout) {
                    return false;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            jedis.close();
        }
    }


    public boolean unlock(String id) {
        Jedis jedis = jedisPool.getResource();
        while (true) {
            String script =
                    "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                            "   return redis.call('del',KEYS[1]) " +
                            "else" +
                            "   return 0 " +
                            "end";
            String result = jedis.eval(script, Collections.singletonList(lock_key),
                    Collections.singletonList(id)).toString();
            if ("1".equals(result)) {
                jedis.close();
                return true;
            } else {
                System.err.println("error!!!");
            }
        }
    }

    public void test() {
        System.out.println("begin");
        long l = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            Jedis jedis = jedisPool.getResource();
            jedis.set(lock_key, "", params);
            jedis.del(lock_key);
            jedis.close();
        }
        long r = System.currentTimeMillis();
        System.out.println((r - l) + " ms");
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("to here");
        long start = System.currentTimeMillis();
        int clientCount = 100000;
        CountDownLatch countDownLatch = new CountDownLatch(clientCount);
        RedisLock redisLock = new RedisLock();

        ExecutorService executorService = Executors.newFixedThreadPool(clientCount);
        for (int i = 0; i < clientCount; i++) {
            executorService.execute(() -> {

                //通过Snowflake算法获取唯一的ID字符串
                String id = UUID.randomUUID().toString();
                try {
                    redisLock.lock(id);
                } finally {
                    redisLock.unlock(id);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        long end = System.currentTimeMillis();


        System.out.println((end - start) + " ms");


    }
}
